package health_system.health_system.websocket.Test;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import health_system.health_system.config.WebSocketConfigurator;
import health_system.health_system.dto.*;
import health_system.health_system.entity.Moment;
import health_system.health_system.entity.MomentMedia;
import health_system.health_system.entity.User;
import health_system.health_system.service.*;
import health_system.health_system.websocket.Test.dto.MomentWebSocketRequest;
import health_system.health_system.websocket.Test.dto.MomentWebSocketResponse;
import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Component;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
@ServerEndpoint(value = "/moment/ws", configurator = WebSocketConfigurator.class)
public class MomentWebSocketServer {
    private static final Map<String, Session> userSessions = new ConcurrentHashMap<>();
    private static final Map<String, ByteArrayOutputStream> fileBuffers = new ConcurrentHashMap<>();
    private static final Map<String, List<String>> pendingMediaUploads = new ConcurrentHashMap<>();
    private static UserService userService;
    private static MomentService momentService;
    private static MomentCommentService commentService;
    private static MomentLikeService likeService;
    private static MomentMediaService mediaService;
    private static String uploadDir;
    private static final ObjectMapper objectMapper;
    
    // 静态初始化块，配置ObjectMapper
    static {
        objectMapper = new ObjectMapper();
        // 注册Java 8日期时间模块
        objectMapper.registerModule(new JavaTimeModule());
        // 禁用将日期时间序列化为时间戳
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    }
    
    @Autowired
    public void setUserService(UserService userService) {
        MomentWebSocketServer.userService = userService;
    }
    
    @Autowired
    public void setMomentService(MomentService momentService) {
        MomentWebSocketServer.momentService = momentService;
    }
    
    @Autowired
    public void setCommentService(MomentCommentService commentService) {
        MomentWebSocketServer.commentService = commentService;
    }
    
    @Autowired
    public void setLikeService(MomentLikeService likeService) {
        MomentWebSocketServer.likeService = likeService;
    }
    
    @Autowired
    public void setMediaService(MomentMediaService mediaService) {
        MomentWebSocketServer.mediaService = mediaService;
    }
    
    @Value("${upload.dir:./uploads/moments}")
    public void setUploadDir(String uploadDir) {
        MomentWebSocketServer.uploadDir = uploadDir;
    }
    
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("---------------------------------朋友圈----------------------------------");
        log.info("朋友圈连接成功 with ID: {}", session.getId());
        log.info("Query string: {}", session.getQueryString());
        log.info("Request parameters: {}", session.getRequestParameterMap());
        log.info("Request URI: {}", session.getRequestURI());
        log.info("Path parameters: {}", session.getPathParameters());
        
        checkUploadDirectory();
        try {
            Map<String, List<String>> params = session.getRequestParameterMap();
            List<String> userIds = params.get("userId");
            
            if (userIds == null || userIds.isEmpty()) {
                log.warn("Missing userId parameter in WebSocket connection");
                closeSession(session, "Missing userId parameter");
                return;
            }
            
            String userId = userIds.get(0);
            log.info("User ID extracted from request: {}", userId);
            
            // Check if we have the user service available
            if (userService == null) {
                log.error("UserService is null, this is likely due to incorrect Spring bean initialization");
                closeSession(session, "Server configuration error: UserService not available");
                return;
            }
            
            // Store session
            userSessions.put(userId, session);
            
            Map<String, Object> response = new HashMap<>();
            response.put("type", "CONNECT_SUCCESS");
            response.put("message", "Moment WebSocket connection successful");
            response.put("success", true);
            
            sendMessage(session, objectMapper.writeValueAsString(response));
            log.info("Moment user connected: {}, current online users: {}", userId, userSessions.size());
        } catch (Exception e) {
            log.error("Error during WebSocket connection opening", e);
            closeSession(session, "Server error: " + e.getMessage());
        }
    }
    
    @OnClose
    public void onClose(Session session) {
        String userId = getUserIdBySession(session);
        if (userId != null) {
            userSessions.remove(userId);
            log.info("Moment user disconnected: {}, current online users: {}", userId, userSessions.size());
        }
        // Clean file buffers
        String sessionId = session.getId();
        fileBuffers.remove(sessionId);
        pendingMediaUploads.remove(sessionId);
    }
    
    @OnMessage
    public void onMessage(String message, Session session) {
        log.debug("Received moment text message: {}", message);
        try {
            MomentWebSocketRequest request = objectMapper.readValue(message, MomentWebSocketRequest.class);
            String userId = getUserIdBySession(session);
            
            if (userId == null) {
                sendError(session, "Unauthenticated user");
                return;
            }
            
            User currentUser = userService.getUserEntityById(Long.valueOf(userId));
            
            if (currentUser == null) {
                sendError(session, "User not found");
                return;
            }
            
            processRequest(request, session, currentUser);
        } catch (Exception e) {
            log.error("Error processing message", e);
            sendError(session, "Failed to process request: " + e.getMessage());
        }
    }
    
    @OnMessage
    public void onBinaryMessage(ByteBuffer byteBuffer, Session session, boolean isLast) throws IOException {
        String sessionId = session.getId();
        ByteArrayOutputStream bufferStream = fileBuffers.computeIfAbsent(sessionId, k -> new ByteArrayOutputStream());
        byte[] bytes = new byte[byteBuffer.remaining()];
        byteBuffer.get(bytes);
        bufferStream.write(bytes);
        
        if (isLast) {
            byte[] fullData = bufferStream.toByteArray();
            fileBuffers.remove(sessionId);
            try {
                ByteBuffer dataBuffer = ByteBuffer.wrap(fullData);
                int metaLength = dataBuffer.getInt();
                if (metaLength < 0 || metaLength > dataBuffer.remaining()) {
                    handleError(session, "Invalid metadata length");
                    return;
                }
                
                byte[] metaBytes = new byte[metaLength];
                dataBuffer.get(metaBytes);
                String metaStr = new String(metaBytes, StandardCharsets.UTF_8);
                Map<String, Object> metadata = objectMapper.readValue(metaStr, Map.class);
                
                String userId = (String) metadata.get("userId");
                String momentId = (String) metadata.get("momentId");
                String type = (String) metadata.get("type");
                String fileExtension = (String) metadata.get("fileExtension");
                
                if (fileExtension == null || fileExtension.isEmpty()) {
                    fileExtension = "png"; // Default to PNG image
                }
                
                byte[] fileData = new byte[dataBuffer.remaining()];
                dataBuffer.get(fileData);
                
                // Generate unique filename and store file
                String fileName = generateUniqueFileName() + "." + fileExtension;
                Path filePath = Paths.get(uploadDir, fileName);
                Files.createDirectories(filePath.getParent());
                Files.write(filePath, fileData);

                // File URL
                String fileUrl = "/api/moments/media/" + fileName;

                // If it's a new moment media upload, add to pending list
                if ("MEDIA_UPLOAD".equals(type)) {
                    pendingMediaUploads.computeIfAbsent(sessionId, k -> new ArrayList<>()).add(fileUrl);
                    
                    // Return upload success response
                    Map<String, Object> response = new HashMap<>();
                    response.put("type", "MEDIA_UPLOAD_SUCCESS");
                    response.put("url", fileUrl);
                    response.put("success", true);
                    sendMessage(session, objectMapper.writeValueAsString(response));
                    
                    log.info("Moment media uploaded successfully: {}", fileUrl);
                } 
                // If it's a moment media forward
                else if ("MEDIA_FORWARD".equals(type)) {
                    forwardMediaToFriends(userId, fileUrl, fileData, type, fileExtension);
                }
                
            } catch (Exception e) {
                log.error("Error processing binary message", e);
                handleError(session, "Media file processing failed: " + e.getMessage());
            }
        }
    }
    
    private void processRequest(MomentWebSocketRequest request, Session session, User currentUser) {
        String type = request.getType();
        MomentWebSocketResponse response = new MomentWebSocketResponse();
        
        try {
            switch (type) {
                case "LOAD_MOMENTS":
                    handleLoadMoments(request, response, currentUser);
                    break;
                case "CREATE_MOMENT":
                    handleCreateMoment(request, response, currentUser);
                    break;
                case "LIKE_MOMENT":
                    handleLikeMoment(request, response, currentUser);
                    break;
                case "COMMENT_MOMENT":
                    handleCommentMoment(request, response, currentUser);
                    break;
                case "DELETE_MOMENT":
                    handleDeleteMoment(request, response, currentUser);
                    break;
                case "DELETE_COMMENT":
                    handleDeleteComment(request, response, currentUser);
                    break;
                case "FINALIZE_MEDIA_UPLOADS":
                    handleFinalizeMediaUploads(request, response, currentUser, session);
                    break;
                default:
                    response = MomentWebSocketResponse.error("Unknown request type: " + type);
                    break;
            }
        } catch (Exception e) {
            log.error("Error processing request", e);
            response = MomentWebSocketResponse.error("Failed to process request: " + e.getMessage());
        }
        
        try {
            String jsonString = objectMapper.writeValueAsString(response);
            sendMessage(session, jsonString);
        } catch (Exception e) {
            log.error("Error serializing response", e);
            // 提供更详细的错误信息
            String errorDetail = e.getMessage();
            if (e.getCause() != null) {
                errorDetail += " | Cause: " + e.getCause().getMessage();
            }
            
            // 如果JSON序列化失败，发送一个简单的错误响应
            Map<String, Object> errorResponse = new HashMap<>();
            errorResponse.put("type", "ERROR");
            errorResponse.put("success", false);
            errorResponse.put("message", "System error: " + errorDetail);
            try {
                // 使用更简单的方式序列化错误响应
                StringBuilder jsonBuilder = new StringBuilder();
                jsonBuilder.append("{");
                jsonBuilder.append("\"type\":\"ERROR\",");
                jsonBuilder.append("\"success\":false,");
                jsonBuilder.append("\"message\":\"System error: ").append(escapeJsonString(errorDetail)).append("\"");
                jsonBuilder.append("}");
                
                sendMessage(session, jsonBuilder.toString());
            } catch (Exception ex) {
                log.error("Failed to send error message", ex);
            }
        }
    }
    
    // 辅助方法：转义JSON字符串
    private String escapeJsonString(String input) {
        if (input == null) {
            return "";
        }
        
        StringBuilder escaped = new StringBuilder();
        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            switch (c) {
                case '\"':
                    escaped.append("\\\"");
                    break;
                case '\\':
                    escaped.append("\\\\");
                    break;
                case '\b':
                    escaped.append("\\b");
                    break;
                case '\f':
                    escaped.append("\\f");
                    break;
                case '\n':
                    escaped.append("\\n");
                    break;
                case '\r':
                    escaped.append("\\r");
                    break;
                case '\t':
                    escaped.append("\\t");
                    break;
                default:
                    // 处理控制字符
                    if (c < 32) {
                        String hex = Integer.toHexString(c);
                        escaped.append("\\u");
                        for (int j = 0; j < 4 - hex.length(); j++) {
                            escaped.append('0');
                        }
                        escaped.append(hex);
                    } else {
                        escaped.append(c);
                    }
            }
        }
        return escaped.toString();
    }
    
    private void handleFinalizeMediaUploads(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser, Session session) {
        String sessionId = session.getId();
        List<String> mediaUrls = pendingMediaUploads.getOrDefault(sessionId, new ArrayList<>());
        
        response.setType("MEDIA_UPLOADS_FINALIZED");
        response.setSuccess(true);
        response.setMessage("Media uploads completed");
        response.setMediaUrls(mediaUrls);
        
        // Clear pending media list
        pendingMediaUploads.remove(sessionId);
    }
    
    private void handleLoadMoments(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser) {
        int page = request.getPage() != null ? request.getPage() : 0;
        int size = request.getSize() != null ? request.getSize() : 10;
        Pageable pageable = PageRequest.of(page, size);

        PageResponseDTO<MomentDTO> momentPage = momentService.getMomentsVisibleToUser(currentUser.getId(), pageable);
        
        response.setType("MOMENTS_DATA");
        response.setSuccess(true);
        response.setMoments(momentPage.getContent());
        response.setTotalPages(momentPage.getTotalPages());
        response.setCurrentPage(page);
        response.setTotalElements((int) momentPage.getTotalElements());
        response.setMessage("Moments data loaded");
    }
    
    private void handleCreateMoment(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser) {
        String content = request.getContent();
        List<String> mediaUrls = request.getMediaUrls() != null ? request.getMediaUrls() : new ArrayList<>();
        
        // Create moment create DTO
        MomentCreateDTO createDTO = new MomentCreateDTO();
        createDTO.setUserId(currentUser.getId());
        createDTO.setContent(content);
        createDTO.setVisibility(request.getVisibility() != null ? 
                request.getVisibility() : Moment.VisibilityType.FRIENDS);
        
        // Convert media URLs to media create DTOs
        if (!mediaUrls.isEmpty()) {
            List<MomentMediaCreateDTO> mediaList = new ArrayList<>();
            for (int i = 0; i < mediaUrls.size(); i++) {
                MomentMediaCreateDTO mediaDTO = new MomentMediaCreateDTO();
                mediaDTO.setMediaUrl(mediaUrls.get(i));
                mediaDTO.setMediaType(MomentMedia.MediaType.IMAGE); // Default to image, can be improved to detect type
                mediaDTO.setOrderIndex(i);
                mediaList.add(mediaDTO);
            }
            createDTO.setMediaList(mediaList);
        }
        
        MomentDTO moment = momentService.createMoment(createDTO);
        
        response.setType("MOMENT_CREATED");
        response.setSuccess(true);
        response.setMoment(moment);
        response.setMessage("Moment created successfully");
        
        // Notify friends
        notifyFriends(currentUser, response);
    }
    
    private void handleLikeMoment(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser) {
        Long momentId = request.getMomentId();
        if (momentId == null) {
            response = MomentWebSocketResponse.error("Moment ID cannot be empty");
            return;
        }
        
        MomentLikeCreateDTO likeCreateDTO = new MomentLikeCreateDTO();
        likeCreateDTO.setMomentId(momentId);
        likeCreateDTO.setUserId(currentUser.getId());
        
        // Check if already liked
        boolean alreadyLiked = likeService.hasUserLikedMoment(currentUser.getId(), momentId);
        
        if (alreadyLiked) {
            // Unlike the moment
            likeService.unlikeMoment(currentUser.getId(), momentId);
            response.setLiked(false);
            response.setMessage("Like removed");
        } else {
            // Like the moment
            MomentLikeDTO likeDTO = likeService.likeMoment(likeCreateDTO);
            response.setLike(likeDTO);
            response.setLiked(true);
            response.setMessage("Moment liked");
        }
        
        // Get updated moment
        MomentDTO moment = momentService.getMomentWithLikeStatus(momentId, currentUser.getId());
        
        response.setType("MOMENT_LIKE_UPDATED");
        response.setSuccess(true);
        response.setMoment(moment);
        
        // Notify moment owner if not current user
        if (!moment.getUserId().equals(currentUser.getId())) {
            notifyUser(moment.getUserId().toString(), createLikeNotification(currentUser, moment));
        }
    }
    
    private void handleCommentMoment(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser) {
        Long momentId = request.getMomentId();
        String content = request.getContent();
        
        if (momentId == null || content == null || content.trim().isEmpty()) {
            response = MomentWebSocketResponse.error("Moment ID and comment content cannot be empty");
            return;
        }
        
        MomentCommentCreateDTO commentCreateDTO = new MomentCommentCreateDTO();
        commentCreateDTO.setMomentId(momentId);
        commentCreateDTO.setUserId(currentUser.getId());
        commentCreateDTO.setContent(content);
        
        // Add comment
        MomentCommentDTO commentDTO = commentService.createComment(commentCreateDTO);
        
        // Get updated moment
        MomentDTO moment = momentService.getMomentById(momentId);
        
        response.setType("MOMENT_COMMENTED");
        response.setSuccess(true);
        response.setMoment(moment);
        response.setComment(commentDTO);
        response.setMessage("Comment added successfully");
        
        // Notify moment owner if not current user
        if (!moment.getUserId().equals(currentUser.getId())) {
            notifyUser(moment.getUserId().toString(), createCommentNotification(currentUser, moment, content));
        }
    }
    
    private void handleDeleteMoment(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser) {
        Long momentId = request.getMomentId();
        
        if (momentId == null) {
            response = MomentWebSocketResponse.error("Moment ID cannot be empty");
            return;
        }
        
        // Verify moment exists and belongs to user
        MomentDTO moment = momentService.getMomentById(momentId);
        if (!moment.getUserId().equals(currentUser.getId())) {
            response = MomentWebSocketResponse.error("You can only delete your own moments");
            return;
        }
        
        // Delete moment
        momentService.deleteMoment(momentId);
        
        response.setType("MOMENT_DELETED");
        response.setSuccess(true);
        response.setMessage("Moment deleted");
        response.setMomentId(momentId);
        
        // Notify friends
        notifyFriendsMomentDeleted(currentUser, momentId);
    }
    
    private void handleDeleteComment(MomentWebSocketRequest request, MomentWebSocketResponse response, User currentUser) {
        Long commentId = request.getCommentId();
        
        if (commentId == null) {
            response = MomentWebSocketResponse.error("Comment ID cannot be empty");
            return;
        }
        
        commentService.deleteComment(commentId);
        
        response.setType("COMMENT_DELETED");
        response.setSuccess(true);
        response.setMessage("Comment deleted");
        response.setCommentId(commentId);
    }
    
    private void notifyFriends(User currentUser, MomentWebSocketResponse response) {
        for (Map.Entry<String, Session> entry : userSessions.entrySet()) {
            String userId = entry.getKey();
            if (!userId.equals(currentUser.getId().toString())) {
                Session friendSession = entry.getValue();
                try {
                    sendMessage(friendSession, objectMapper.writeValueAsString(response));
                } catch (Exception e) {
                    log.error("Failed to notify friend", e);
                }
            }
        }
    }
    
    private void notifyFriendsMomentDeleted(User currentUser, Long momentId) {
        MomentWebSocketResponse response = new MomentWebSocketResponse();
        response.setType("MOMENT_DELETED");
        response.setSuccess(true);
        response.setMessage("A friend deleted a moment");
        response.setMomentId(momentId);
        
        for (Map.Entry<String, Session> entry : userSessions.entrySet()) {
            String userId = entry.getKey();
            if (!userId.equals(currentUser.getId().toString())) {
                Session friendSession = entry.getValue();
                try {
                    sendMessage(friendSession, objectMapper.writeValueAsString(response));
                } catch (Exception e) {
                    log.error("Failed to notify friend about deleted moment", e);
                }
            }
        }
    }
    
    private void forwardMediaToFriends(String userId, String fileUrl, byte[] fileData, String type, String fileExtension) {
        for (Map.Entry<String, Session> entry : userSessions.entrySet()) {
            String friendId = entry.getKey();
            if (!friendId.equals(userId)) {
                Session friendSession = entry.getValue();
                
                try {
                    // Create forward metadata
                    Map<String, Object> forwardMeta = new HashMap<>();
                    forwardMeta.put("from", userId);
                    forwardMeta.put("to", friendId);
                    forwardMeta.put("type", type);
                    forwardMeta.put("fileUrl", fileUrl);
                    forwardMeta.put("fileExtension", fileExtension);
                    
                    byte[] forwardMetaBytes = objectMapper.writeValueAsString(forwardMeta).getBytes(StandardCharsets.UTF_8);
                    int forwardMetaLength = forwardMetaBytes.length;
                    
                    // Create forward buffer
                    ByteBuffer forwardBuffer = ByteBuffer.allocate(4 + forwardMetaLength + fileData.length);
                    forwardBuffer.putInt(forwardMetaLength);
                    forwardBuffer.put(forwardMetaBytes);
                    forwardBuffer.put(fileData);
                    forwardBuffer.flip();
                    
                    // Forward to friend
                    if (friendSession.isOpen()) {
                        synchronized (friendSession) {
                            friendSession.getBasicRemote().sendBinary(forwardBuffer);
                        }
                    }
                } catch (IOException e) {
                    log.error("Failed to forward media file", e);
                }
            }
        }
    }
    
    private Map<String, Object> createLikeNotification(User liker, MomentDTO moment) {
        Map<String, Object> notification = new HashMap<>();
        notification.put("type", "NOTIFICATION");
        notification.put("notificationType", "LIKE");
        notification.put("userId", liker.getId());
        notification.put("username", liker.getUsername());
        notification.put("userAvatar", liker.getAvatarUrl());
        notification.put("momentId", moment.getId());
        notification.put("message", liker.getUsername() + " liked your moment");
        notification.put("timestamp", LocalDateTime.now());
        return notification;
    }
    
    private Map<String, Object> createCommentNotification(User commenter, MomentDTO moment, String commentContent) {
        Map<String, Object> notification = new HashMap<>();
        notification.put("type", "NOTIFICATION");
        notification.put("notificationType", "COMMENT");
        notification.put("userId", commenter.getId());
        notification.put("username", commenter.getUsername());
        notification.put("userAvatar", commenter.getAvatarUrl());
        notification.put("momentId", moment.getId());
        notification.put("commentContent", commentContent);
        notification.put("message", commenter.getUsername() + " commented on your moment");
        notification.put("timestamp", LocalDateTime.now());
        return notification;
    }
    
    private void notifyUser(String userId, Map<String, Object> notification) {
        Session targetSession = userSessions.get(userId);
        if (targetSession != null && targetSession.isOpen()) {
            try {
                sendMessage(targetSession, objectMapper.writeValueAsString(notification));
            } catch (Exception e) {
                log.error("Failed to send notification", e);
            }
        }
    }
    
    private String getUserIdBySession(Session session) {
        return userSessions.entrySet().stream()
                .filter(entry -> entry.getValue().equals(session))
                .map(Map.Entry::getKey)
                .findFirst().orElse(null);
    }
    
    private void sendMessage(Session session, String message) {
        if (session != null && session.isOpen()) {
            try {
                synchronized (session) {
                    session.getBasicRemote().sendText(message);
                }
            } catch (IOException e) {
                log.error("Failed to send message", e);
            }
        }
    }
    
    private void sendError(Session session, String errorMsg) {
        Map<String, Object> error = new HashMap<>();
        error.put("type", "ERROR");
        error.put("message", errorMsg);
        error.put("success", false);
        try {
            sendMessage(session, objectMapper.writeValueAsString(error));
        } catch (Exception e) {
            log.error("Failed to send error message", e);
        }
    }
    
    private void handleError(Session session, String errorMsg) {
        Map<String, Object> err = new HashMap<>();
        err.put("type", "ERROR");
        err.put("message", errorMsg);
        err.put("success", false);
        try {
            sendMessage(session, objectMapper.writeValueAsString(err));
        } catch (Exception e) {
            log.error("Failed to send error message", e);
        }
    }
    
    private void closeSession(Session session, String reason) {
        try {
            if (session.isOpen()) {
                session.close(new CloseReason(
                        CloseReason.CloseCodes.VIOLATED_POLICY, reason));
            }
        } catch (IOException e) {
            log.error("Error closing session", e);
        }
    }
    
    private String generateUniqueFileName() {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        String time = LocalDateTime.now().format(fmt);
        int rand = (int) (Math.random() * 1000);
        return String.format("moment_%s_%03d", time, rand);
    }
    
    private void checkUploadDirectory() {
        try {
            Path path = Paths.get(uploadDir);
            if (!Files.exists(path)) {
                Files.createDirectories(path);
                log.info("Created moment upload directory: {}", path.toAbsolutePath());
            }
        } catch (IOException e) {
            log.error("Failed to create moment directory", e);
        }
    }
    
    @OnError
    public void onError(Session session, Throwable error) {
        String userId = getUserIdBySession(session);
        log.error("Moment WebSocket Error for user {}: {}", userId, error.getMessage(), error);
        sendError(session, "Server error: " + error.getMessage());
    }
} 